home *** CD-ROM | disk | FTP | other *** search
/ Delphi 2 - Developers' Solutions / Delphi 2 Developers' Solutions.iso / dds / chap06 / howto05 / delphi10 / drwsutl6.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-01-09  |  12.6 KB  |  376 lines

  1. unit Drwsutl6;
  2.  
  3. interface
  4. uses
  5.   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  6.   Forms, Dialogs, StdCtrls, Buttons, ExtCtrls, ShellAPI, FileCtrl;
  7.  
  8. type
  9.  
  10.   File_BitMap = class( TObject )
  11.   public
  12.     Bitmap_Handle    : HBitmap;   { Holds the DIB when done               }
  13.     Width            : Longint;   { Holds the pixel width when done       }
  14.     Height           : Longint;   { Holds the pixel height when done      }
  15.     The_File         : File;      { File variable for internal use        }
  16.     The_Name         : String;    { Holds the file name                   }
  17.     Bits_Handle      : THandle;   { temporary holder for the DIB          }
  18.     Bits_Byte_Size   : Longint;   { temporary holder for the              }
  19.                                   { byte length of the DIB                }
  20.     Error_Status     : Integer;   { code for error condition on the DIB   }
  21.  
  22.     constructor Create;
  23.     procedure Initialize( The_DIB_Name : String );
  24.     destructor Destroy;
  25.     procedure Get_Bitmap_Data;
  26.     function Get_Bitmap : HBitmap;
  27.     function Load_Bitmap_File : Boolean;
  28.     function Open_DIB : Boolean;
  29.     function Get_Error_Status : Integer;
  30.     procedure Get_DIB_Dimensions( var The_Width  ,
  31.                                       The_Height   : Longint );
  32.   end;
  33.  
  34. function CreateBitmapThumbNailFromBitmap( SourceBMP: TBitmap;
  35.                                           TargetWidth ,
  36.                                           TargetHeight : Integer ) : TBitmap;
  37.  
  38. implementation
  39.  
  40. procedure AHIncr; FAR; EXTERNAL 'KERNEL' INDEX 114;
  41.  
  42. function CreateBitmapThumbNailFromBitmap( SourceBMP: TBitmap;
  43.                                           TargetWidth ,
  44.                                           TargetHeight : Integer ) : TBitmap;
  45. var OutputBMP : TBitmap;
  46.     HoldingBMP : TBitmap;
  47.     TotalSourceColsPerOutputCol,
  48.     TotalSourceRowsPerOutputRow,
  49.     Counter_1 ,
  50.     Counter_2 ,
  51.     Counter_3 : Integer;
  52.     CurrentColor : Longint;
  53.     CurrentRowPointer,
  54.     CurrentColPointer,
  55.     BestLineSoFar ,
  56.     TotalColorsInWork : Integer;
  57.     MaxColorsSoFar    : Integer;
  58. begin
  59.   { if source smaller than or equal to thumbnail, stretchdraw and leave }
  60.   if (( SourceBMP.Width <= TargetWidth ) and
  61.       ( SourceBMP.Height <= TargetHeight )) then
  62.   begin
  63.     OutputBMP := TBitmap.Create;
  64.     OutputBMP.Height := TargetHeight;
  65.     OutputBMP.Width := TargetWidth;
  66.     OutputBMP.Canvas.StretchDraw( Rect( 0 , 0 , TargetWidth , TargetHeight ) ,
  67.      SourceBMP );
  68.     CreateBitmapThumbNailFromBitmap := OutputBMP;
  69.     exit;
  70.   end;
  71.   { Otherwise do thumbnail algorithm }
  72.   { Create the interim holding bitmap; it will hold full width but resized # rows }
  73.   HoldingBMP := TBitmap.Create;
  74.   HoldingBMP.Width := SourceBMP.Width;
  75.   HoldingBMP.Height := TargetHeight;
  76.   { Create the final output bitmap; it will hold the resized values in both h & w }
  77.   OutputBMP := TBitmap.Create;
  78.   OutputBMP.Width := TargetWidth;
  79.   OutputBMP.Height := TargetHeight;
  80.   { Determine the total source rows and cols per output row and col }
  81.   TotalSourceRowsPerOutputRow := ( SourceBMP.Height div TargetHeight );
  82.   if ( SourceBMP.Height mod TargetHeight ) <> 0 then
  83.    Inc( TotalSourceRowsPerOutputRow );
  84.   TotalSourceColsPerOutputCol := ( SourceBMP.Width div TargetWidth );
  85.   if ( SourceBMP.Width mod TargetWidth ) <> 0 then
  86.    Inc( TotalSourceColsPerOutputCol );
  87.   { Start resizing by setting initial row pointer }
  88.   CurrentRowPointer := 0;
  89.   { Loop through desired number of output rows                       }
  90.   { Result will add row per group with highest color density to dest }
  91.   for Counter_1 := 1 to TargetHeight do
  92.   begin
  93.     { Reset colors per line, best cols per line, and best line pointers }
  94.     { Check all the lines in a group against each other }
  95.     TotalColorsInWork := 0;
  96.     MaxColorsSoFar := 0;
  97.     BestLineSoFar := 0;
  98.     for Counter_2 := 1 to TotalSourceRowsPerOutputRow do
  99.     begin
  100.       { Keep moving down the image }
  101.       Inc( CurrentRowPointer );
  102.       if CurrentRowPointer > SourceBMP.Height then break;
  103.       { Start with no color }
  104.       CurrentColor := -1;
  105.       TotalColorsInWork := 0;
  106.       { Actually scan the pixels }
  107.       for Counter_3 := 1 to SourceBMP.Width do
  108.       begin
  109.         { if the current pixel value is different than the stored one }
  110.         If SourceBMP.Canvas.Pixels[ Counter_3 - 1 , CurrentRowPointer - 1 ] <>
  111.          CurrentColor then
  112.         begin
  113.           { Make the new color the stored one }
  114.           CurrentColor := SourceBMP.Canvas.Pixels[ Counter_3 - 1 ,
  115.            CurrentRowPointer - 1 ];
  116.           { Increment total colors in the line }
  117.           Inc( TotalColorsInWork );
  118.         end;
  119.       end;
  120.       { At the end of the line, if there are more colors in the }
  121.       { current line than the previous best line, then }
  122.       if TotalColorsInWork > MaxColorsSoFar then
  123.       begin
  124.         { Set the new max to the current value }
  125.         MaxColorsSoFar := TotalColorsInWork;
  126.         { Set the new best line to the current pointer }
  127.         BestLineSoFar := CurrentRowPointer;
  128.       end;
  129.       { Reset the total colors being checked }
  130.       TotalColorsInWork := 0;
  131.     end;
  132.     MaxColorsSoFar := 0;
  133.     { Once best line is determined, copy all its pixels to the holding bmp }
  134.     for Counter_3 := 1 to SourceBMP.Width do
  135.     begin
  136.       HoldingBMP.Canvas.Pixels[ Counter_3 - 1 , Counter_1 - 1 ] :=
  137.        SourceBMP.Canvas.Pixels[ Counter_3 - 1 , BestLineSoFar - 1 ];
  138.     end;
  139.   end;
  140.   { Then resize by setting initial col pointer }
  141.   CurrentColPointer := 0;
  142.   { Loop through desired number of output cols                       }
  143.   { Result will add col per group with highest color density to dest }
  144.   for Counter_1 := 1 to TargetWidth do
  145.   begin
  146.     { Reset colors per line, best cols per line, and best line pointers }
  147.     TotalColorsInWork := 0;
  148.     MaxColorsSoFar := 0;
  149.     BestLineSoFar := 0;
  150.     { Check all the lines in a group against each other }
  151.     for Counter_2 := 1 to TotalSourceColsPerOutputCol do
  152.     begin
  153.       { Keep moving down the image }
  154.       Inc( CurrentColPointer );
  155.       if CurrentColPointer > HoldingBMP.Width then break;
  156.       { Start with no color }
  157.       CurrentColor := -1;
  158.       { Actually scan the pixels }
  159.       for Counter_3 := 1 to HoldingBMP.Height do
  160.       begin
  161.         { if the current pixel value is different than the stored one }
  162.         If HoldingBMP.Canvas.Pixels[ CurrentColPointer - 1 , Counter_3 - 1 ] <>
  163.          CurrentColor then
  164.         begin
  165.           { Make the new color the stored one }
  166.           CurrentColor := HoldingBMP.Canvas.Pixels[ CurrentColPointer - 1 ,
  167.            Counter_3 - 1 ];
  168.           { Increment total colors in the line }
  169.           Inc( TotalColorsInWork );
  170.         end;
  171.       end;
  172.       { At the end of the line, if there are more colors in the }
  173.       { current line than the previous best line, then }
  174.       if TotalColorsInWork > MaxColorsSoFar then
  175.       begin
  176.         { Set the new max to the current value }
  177.         MaxColorsSoFar := TotalColorsInWork;
  178.         { Set the new best line to the current pointer }
  179.         BestLineSoFar := CurrentColPointer;
  180.       end;
  181.       { Reset the total colors being checked }
  182.       TotalColorsInWork := 0;
  183.     end;
  184.     { Once best line is determined, copy all its pixels to the holding bmp }
  185.     for Counter_3 := 1 to HoldingBMP.Height do
  186.     begin
  187.       OutputBMP.Canvas.Pixels[ Counter_1 - 1 , Counter_3 - 1 ] :=
  188.        HoldingBMP.Canvas.Pixels[ BestLineSoFar - 1 , Counter_3 - 1 ];
  189.     end;
  190.   end;
  191.   { Finally, output the thumbnail image }
  192.   CreateBitmapThumbNailFromBitmap := OutputBMP;
  193.   { And free the working copy }
  194.   HoldingBMP.Free;
  195. end;
  196.  
  197. { This creates a file bitmap object }
  198. constructor File_BitMap.Create;
  199. begin
  200.   { call inherited FIRST! }
  201.   inherited Create;
  202.   { Zero out the data elements }
  203.   Bitmap_Handle := 0;
  204.   The_Name := '';
  205. end;
  206.  
  207. { This procedure sets up the bitmap filename to load }
  208. procedure File_BitMap.Initialize( The_DIB_Name : String );
  209. begin
  210.   The_Name := The_DIB_Name;
  211. end;
  212.  
  213. { This is the destructor procedure }
  214. destructor File_BitMap.Destroy;
  215. begin
  216.   { Assume bitmap handle given to TBitmap and cleared there }
  217.   { call inherited last }
  218.   inherited destroy;
  219. end;
  220.  
  221. { This method copies the bitmap bits data from the file into memory. Since }
  222. { copying cannot cross a segment (64K) boundary, segment arithmetic must   }
  223. { be done on the fly.  A LongType type was created to simplify this process}
  224. procedure File_BitMap.Get_Bitmap_Data;
  225.  
  226. type
  227.   LongType = record
  228.   case Word of
  229.     0: ( Ptr  : Pointer );
  230.     1: ( Long : Longint );
  231.     2: ( Lo   : Word;
  232.          Hi   : Word    );
  233.   end;
  234. var
  235.   Count   : Longint;
  236.   Start,
  237.   ToAddr,
  238.   Bits    : LongType;
  239. begin
  240.   Start.Long := 0;
  241.   Bits.Ptr := GlobalLock( Bits_Handle );
  242.   Count := Bits_Byte_Size - Start.Long;
  243.   while Count > 0 do
  244.   begin
  245.     ToAddr.Hi := Bits.Hi + ( Start.Hi * OFS( AHIncr ));
  246.     ToAddr.Lo := Start.Lo;
  247.     if Count > $4000 then Count := $4000;
  248.     BlockRead( The_File , ToAddr.Ptr^ , Count );
  249.     Start.Long := Start.Long + Count;
  250.     Count := Bits_Byte_Size - Start.Long;
  251.   end;
  252.   GlobalUnlock( Bits_Handle );
  253. end;
  254.  
  255. { This returns the handle to the stored bitmap }
  256. function File_BitMap.Get_Bitmap : HBitmap;
  257. begin
  258.   Get_Bitmap := Bitmap_Handle;
  259. end;
  260.  
  261. { This is the function to call to load a bitmap file of any size }
  262. { If no errors occur it returns true, otherwise false; use GEC   }
  263. { (Some portions of this code are copyright Borland Intl, 1990.) }
  264. function File_BitMap.Load_Bitmap_File : Boolean;
  265. var
  266.   Test_Win30_Bitmap : Longint;
  267.   Memory_DC         : HDC;
  268.   The_IO_Result     : Word;
  269. begin
  270.   Error_Status := 0;
  271.   Load_Bitmap_File := false;
  272.   AssignFile( The_File , The_Name );
  273.   {$I-}
  274.   Reset( The_File , 1 );
  275.   Seek( The_File , 14 );
  276.   BlockRead( The_File , Test_Win30_Bitmap , SizeOf( Test_Win30_Bitmap ));
  277.   {$I+}
  278.   The_IO_Result := IOResult;
  279.   If The_IO_Result <> 0 then
  280.   begin
  281.     Error_Status := -1;
  282.   end
  283.   else
  284.   begin
  285.     if Test_Win30_Bitmap = 40 then
  286.     begin
  287.       if Open_DIB then
  288.       begin
  289.         Load_Bitmap_File := true;
  290.       end;
  291.     end
  292.     else
  293.     begin
  294.       Error_Status := -2;
  295.     end;
  296.     CloseFile( The_File );
  297.   end;
  298. end;
  299.  
  300. { This does the actual loading of the bitmap's info }
  301. function File_BitMap.Open_DIB : Boolean;
  302. var
  303.   Bit_Count         : Word;
  304.   Size              : Word;
  305.   Long_Width        : Longint;
  306.   DC_Handle         : HDC;
  307.   Bits_Ptr          : Pointer;
  308.   Bitmap_Info       : PBitmapInfo;
  309.   New_Bitmap_Handle : THandle;
  310.   New_Pixel_Width,
  311.   New_Pixel_Height  : Word;
  312. begin
  313.   Open_DIB := true;
  314.   Seek( The_File , 28 );
  315.   BlockRead( The_File , Bit_Count , SizeOf( Bit_Count ));
  316.   if Bit_Count <= 8 then
  317.   begin
  318.     Size := SizeOf( TBitmapInfoHeader ) + (( 1 SHL Bit_Count )
  319.      * SizeOf( TRGBQuad ));
  320.     Bitmap_Info := MemAlloc( Size );
  321.     Seek( The_File , SizeOf( TBitmapFileHeader ));
  322.     BlockRead( The_File , Bitmap_Info^ , Size );
  323.     New_Pixel_Width := Bitmap_Info^.bmiHeader.biWidth;
  324.     New_Pixel_Height := Bitmap_Info^.bmiHeader.biHeight;
  325.     Long_Width := ((( New_Pixel_Width * Bit_Count ) + 31 ) div 32 ) * 4;
  326.     Bitmap_Info^.bmiHeader.biSizeImage := Long_Width * New_Pixel_Height;
  327.     GlobalCompact( -1 );
  328.     Bits_Handle := GlobalAlloc( gmem_Moveable or gmem_Zeroinit ,
  329.                                 Bitmap_Info^.bmiHeader.biSizeImage );
  330.     Bits_Byte_Size := Bitmap_Info^.bmiHeader.biSizeImage;
  331.     Get_Bitmap_Data;
  332.     DC_Handle := CreateDC( 'Display' , nil , nil , nil );
  333.     Bits_Ptr := GlobalLock( Bits_Handle );
  334.     New_Bitmap_Handle :=
  335.     CreateDIBitmap( DC_Handle , Bitmap_Info^.bmiHeader ,
  336.                     cbm_Init , Bits_Ptr , Bitmap_Info^ , 0 );
  337.     DeleteDC( DC_Handle );
  338.     GlobalUnlock( Bits_Handle );
  339.     GlobalFree( Bits_Handle );
  340.     FreeMem( Bitmap_Info , Size );
  341.     if New_Bitmap_Handle <> 0 then
  342.     begin
  343.       if Bitmap_Handle <> 0 then DeleteObject( Bitmap_Handle );
  344.       Bitmap_Handle := New_Bitmap_Handle;
  345.       Width := New_Pixel_Width;
  346.       Height := New_Pixel_Height;
  347.     end
  348.     else
  349.     begin
  350.       Open_DIB := false;
  351.       Error_Status := -4;
  352.     end;
  353.   end
  354.   else
  355.   begin
  356.     Open_DIB := false;
  357.     Error_Status := -3;
  358.   end;
  359. end;
  360.  
  361. { This is an OOP return of the error variable }
  362. function File_BitMap.Get_Error_Status : Integer;
  363. begin
  364.   Get_Error_Status := Error_Status;
  365. end;
  366.  
  367. { This is an OOP return of the dimensions of the DIB }
  368. procedure File_BitMap.Get_DIB_Dimensions( var The_Width  ,
  369.                                               The_Height   : Longint );
  370. begin
  371.   The_Width := Width;
  372.   The_Height := Height;
  373. end;
  374.  
  375. end.
  376.